package api

import (
	"context"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"io"
	"mxshop-api/user-web/forms"
	"mxshop-api/user-web/global"
	"mxshop-api/user-web/global/response"
	middlewares "mxshop-api/user-web/middleware"
	"mxshop-api/user-web/models"
	"mxshop-api/user-web/proto"
	"net/http"
	"strconv"
	"time"
)

func GetUserList(ctx *gin.Context) {
	//获取用户信息
	claims, _ := ctx.Get("claims")
	currentUser := claims.(*models.CustomClaims)
	zap.S().Infof("访问用户: %d", currentUser.Id)
	//分页参数
	pn := ctx.DefaultQuery("pn", "0")
	pnInt, _ := strconv.Atoi(pn) //转换成int类型
	pSize := ctx.DefaultQuery("psize", "10")
	pSizeInt, _ := strconv.Atoi(pSize)
	// 连接用户服务
	resp, err := global.UserSrvClient.GetUserList(context.Background(), &proto.PageInfo{
		Pn:    uint32(pnInt),
		PSize: uint32(pSizeInt),
	})
	if err != nil {
		zap.S().Errorw("[GetUserList] 查询 【用户列表】 失败")
		HandlerGrpcErrorToHttp(ctx, err)
		return
	}

	result := make([]interface{}, 0)
	for _, val := range resp.Data {
		unix := time.Unix(int64(val.BirthDay), 0)
		user := response.UserResponse{
			Id:       val.Id,
			NickName: val.NickName,
			BirthDay: response.JsonTime(unix),
			Gender:   val.Gender,
			Mobile:   val.Mobile,
		}
		result = append(result, user)
	}
	ctx.JSON(http.StatusOK, result)
	zap.S().Debug("获取用户列表页")
}

// PassWordLogin 密码登录
func PassWordLogin(ctx *gin.Context) {

	// 1. 表单验证
	var loginForm forms.PassWordLoginForm
	if err := ctx.ShouldBind(&loginForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		HandlerValidatorError(ctx, err)
		return
	}
	//校验图形验证码
	if !store.Verify(loginForm.CaptchaId, loginForm.Captcha, true) {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"captcha": "验证码错误",
		})
		return
	}
	// 3. 获取用户信息
	rsp, err := global.UserSrvClient.GetUserByMobile(context.Background(), &proto.MobileRequest{Mobile: loginForm.Mobile})
	if err != nil {
		zap.S().Errorw("[PassWordLogin] 获取用户失败", "err", err)
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				ctx.JSON(http.StatusBadRequest, gin.H{"mobile": "用户不存在"})
			default:
				ctx.JSON(http.StatusInternalServerError, gin.H{"error": e.Message(), "msg": "登录失败"})
			}
		}
		return
	}
	// 4. 检查密码
	passRsp, passErr := global.UserSrvClient.CheckPassWord(context.Background(), &proto.CheckPassWordInfo{
		Password:          loginForm.PassWord,
		EncryptedPassword: rsp.PassWord,
	})
	if passErr != nil {
		zap.S().Errorw("[PassWordLogin] 密码验证失败", "err", passErr)
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "登录失败", "error": passErr.Error()})
		return
	}
	if passRsp.Success {
		ResponseUserInfo(ctx, rsp, err)
	} else {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "密码错误"})
	}
}

func Register(ctx *gin.Context) {
	registerForm := forms.RegisterForm{}
	//表单验证
	if err := ctx.ShouldBind(&registerForm); err != nil {
		if errors.Is(err, io.EOF) {
			ctx.JSON(http.StatusBadRequest, gin.H{"msg": "请求体为空"})
			return
		}
		zap.S().Errorw("表单绑定失败", "err", err)
		HandlerValidatorError(ctx, err)
		return
	}
	// 1.验证码校验
	client := redis.NewClient(&redis.Options{
		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisInfo.Host, global.ServerConfig.RedisInfo.Port),
	})
	val, err := client.Get(context.Background(), fmt.Sprintf("smscode:%s", registerForm.Mobile)).Result()
	if errors.Is(err, redis.Nil) || registerForm.Code != val {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": "验证码错误",
		})
		return
	}
	// 2. 连接用户服务
	user, err := global.UserSrvClient.CreateUser(context.Background(), &proto.CreateUserInfo{
		NickName: registerForm.Mobile,
		Mobile:   registerForm.Mobile,
		PassWord: registerForm.PassWord,
	})
	if err != nil {
		zap.S().Errorf("[Register] 查询 【新建用户失败】:%s", err.Error())
		HandlerGrpcErrorToHttp(ctx, err)
		return
	}
	zap.S().Infof("创建用户:%v", user)
	ResponseUserInfo(ctx, user, err)
}

func ResponseUserInfo(ctx *gin.Context, user *proto.UserInfoResponse, err error) {

	//生成token
	j := middlewares.NewJWT()
	//签名
	claims := models.CustomClaims{
		Id:          uint(user.Id),
		NickName:    user.NickName,
		AuthorityId: uint(user.Role),
		StandardClaims: jwt.StandardClaims{
			NotBefore: time.Now().Unix(),               //签名生效时间
			ExpiresAt: time.Now().Unix() + 60*60*24*30, //过期时间
			Issuer:    "seina",                         //认证机构
		},
	}

	token, err := j.CreateToken(claims)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"msg": "生成token失败"})
		return
	}
	//登录成功 返回信息
	ctx.JSON(http.StatusOK, gin.H{
		"id":         user.Id,
		"nick_name":  user.NickName,
		"token":      token,
		"expired_at": (time.Now().Unix() + 60*60*24*30) * 1000,
	})
}

func GetUserByMobile(ctx *gin.Context) {

}

func GetUserById(ctx *gin.Context) {

}
func CreateUser(ctx *gin.Context) {

}
func UpdateUser(ctx *gin.Context) {

}

func CheckPassWord(ctx *gin.Context) {

}
